package com.redis.data.seckillshopping.handler;

import com.redis.data.seckillshopping.aop.RequestLogAspect;
import com.redis.data.seckillshopping.common.Result;
import com.redis.data.seckillshopping.enums.RequestCodeEnum;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import javax.validation.Path;
import java.util.Iterator;
import java.util.Set;

/**
 * @author 哲思小辉
 * @version 1.0.0
 * @ClassName GlobalExceptionHandler.java
 * @Description 异常处理类
 * @Param
 * @createTime 2020年03月25日 11:31:00
 */
@ControllerAdvice
@Slf4j
@NoArgsConstructor
public class GlobalExceptionHandler {


    @ExceptionHandler({Exception.class})
    @ResponseBody
    public Result handler(Exception e) {

        // 异常的时候移除对应信息，避免内存溢出
        Long aLong = RequestLogAspect.startTimes.get();
        if (aLong != null) {
            RequestLogAspect.startTimes.remove();
        }
        // 接口参数验证
        if (e instanceof ConstraintViolationException) {
            log.error("接口参数异常：{}", e.getMessage());
            Set<ConstraintViolation<?>> constraintViolations = ((ConstraintViolationException) e).getConstraintViolations();
            ConstraintViolation<?> next = constraintViolations.iterator().next();
            Path propertyPath = next.getPropertyPath();
            Path.Node lastPathNode = null;
            Iterator<Path.Node> iterator = propertyPath.iterator();
            while (iterator.hasNext()) {
                lastPathNode = iterator.next();
            }
            // 如果要返回字段就可以使用这个 name ，一般前端直接展示的话最好每一个判断里面都写message
            String name = lastPathNode == null ? "" : lastPathNode.getName();
            return new Result(RequestCodeEnum.FAILURE.code, next.getMessage());
        } else if (e instanceof MethodArgumentNotValidException) {
            log.error("请求参数异常：{}", e.getMessage());
            MethodArgumentNotValidException ex = (MethodArgumentNotValidException) e;
            BindingResult bindingResult = ex.getBindingResult();
            return new Result(RequestCodeEnum.FAILURE.code, bindingResult.getFieldError().getDefaultMessage());
        } else if (e instanceof NullPointerException) {
            log.error("空指针异常：{}", e);
        } else if (e instanceof Exception) {
            log.error("请求异常：{}", e.getMessage());
            return new Result(RequestCodeEnum.FAILURE.code, e.getMessage());
        } else {
            log.error("系统异常:{}", e);
        }

        return Result.failure();
    }
}

